package transport.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.*;
import io.netty.channel.nio.NioEventLoopGroup;
import org.apache.log4j.Logger;
import transport.handler.AcceptorHandler;
import transport.handler.ProtocolDecoder;
import transport.handler.ProtocolEncoder;

public class NettyProcessor implements NettyConfig {

    private static final Logger logger = Logger.getLogger(NettyProcessor.class);

    private final ServerBootstrap bootstrap;

    public NettyProcessor() {
        bootstrap = new ServerBootstrap();
    }

    private EventLoopGroup parentGroup;

    private EventLoopGroup childGroup;

    private Class channelClass;

    private ChannelFuture future;

    public void setParentGroup() {
        parentGroup = new NioEventLoopGroup();
    }

    public void setParentGroup(int nThreads) {
        parentGroup = new NioEventLoopGroup(nThreads);
    }

    public void setChildGroup() {
        childGroup = new NioEventLoopGroup();
    }

    public void setChildGroup(int nThreads) {
        childGroup = new NioEventLoopGroup(nThreads);
    }

    public void setChannel(Class channelClass) {
        this.channelClass = channelClass;
    }

    public void setHandler() {
        validate();
        bootstrap.group(parentGroup, childGroup);
        bootstrap.channel(channelClass);
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast("protocolDecoder", new ProtocolDecoder());
                pipeline.addLast("protocolEncoder", new ProtocolEncoder());
                pipeline.addLast("acceptorHandler", new AcceptorHandler());
            }
        }).option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, true);
    }

    public void bind(int port) {
        bind(port, true);
    }

    public void bind(int port, boolean sync) {
        logger.info("服务器监听端口(" + port + ")");
        future = bootstrap.bind(port);
    }

    public void start(boolean sync) {
        try {
            future.sync();
            logger.info("服务器成功启动");
            if (sync) {
                future.channel().closeFuture().sync();
            } else {
                future.channel().closeFuture();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            childGroup.shutdownGracefully();
            parentGroup.shutdownGracefully();
        }

        logger.info("服务器关闭");
    }

    private void validate() {
        if (parentGroup == null
                || childGroup == null
                || channelClass == null) {
            throw new NullPointerException("parentGroup == null " +
                    "|| childGroup == null " +
                    "|| channelClass == null");
        }
    }
}
